﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpObjects.XpathToObjects;

namespace SharpObjects.XpathToObjects_Test
{
    class Program
    {
        static void Main(string[] args)
        {
            SingleObjectSingleObjectTraceTest();
            SingleObjectMultiObjectTraceTest();
        }

        static void Verify<T>(T value1, T value2, string xpath)
        {
            if(!value1.Equals(value2))
            {
                throw new ArgumentException("XPATH '" + xpath + "' was not evaluated correctly");
            }
        }

        static void VerifyEnumerable<T>(IEnumerable<T> value1, IEnumerable<T> value2, string xpath )
        {
            if(value1 == null || value2 == null)
            {
                throw new ArgumentException("XPATH '" + xpath + "' was not evaluated correctly");
            }

            List<T> list1 = new List<T>();
            list1.AddRange(value1);

            List<T> list2 = new List<T>();
            list2.AddRange(value2);

            Verify(list1.Count, list2.Count, xpath);
            
            for(int k = 0; k < list1.Count; k++)
            {
                Verify(list1[k], list2[k], xpath);
            }
        }

        static void SingleObjectSingleObjectTraceTest()
        {
            XPathParser parser = new XPathParser();

            try
            {
                DataModel dataModel = new DataModel();
                dataModel.Initialize1();

                XpathProcessor processor = new XpathProcessor();
                string xpathString;
                {
                    xpathString = "/Message";
                    List<PathElement> xpath = parser.Parse(xpathString);
                    string message = processor.SelectObject<string>(dataModel, xpath);
                    Verify(dataModel.Message, message, xpathString);
                }

                xpathString = "Message";
                string message2 = processor.SelectObject<string>(dataModel, xpathString);
                Verify(dataModel.Message, message2, xpathString);

                //string message3 = processor.SelectObject<string>(dataModel, "//Message");

                xpathString = "/Message/Length";
                int messageLength = processor.SelectObject<int>(dataModel, xpathString);
                Verify(dataModel.Message.Length, messageLength, xpathString);

                xpathString = "/AvailableRoles";
                string[] availableRoles = processor.SelectObject<string[]>(dataModel, xpathString);
                VerifyEnumerable(dataModel.AvailableRoles, availableRoles, xpathString);

                xpathString = "/AvailableRoles[2]";
                string role2 = processor.SelectObject<string>(dataModel, xpathString);
                Verify(dataModel.AvailableRoles[2], role2, xpathString);

                xpathString = "/Options";
                List<string> options = processor.SelectObject<List<string>>(dataModel, xpathString);
                VerifyEnumerable(dataModel.Options, options, xpathString);

                xpathString = "/Options/Count";
                int optionsCount = processor.SelectObject<int>(dataModel, xpathString);
                Verify(dataModel.Options.Count, optionsCount, xpathString);

                xpathString = "/Options[1]";
                string option1 = processor.SelectObject<string>(dataModel, xpathString);
                Verify(dataModel.Options[1], option1, xpathString);

                xpathString = "/Options[1]/Length";
                int option1Length = processor.SelectObject<int>(dataModel, xpathString);
                Verify(dataModel.Options[1].Length, option1Length, xpathString);

                xpathString = "/Organizations[org1]";
                string organization1 = processor.SelectObject<string>(dataModel, xpathString);
                Verify(dataModel.Organizations["org1"], organization1, xpathString);

                xpathString = "/Users[2]/Roles";
                string[] user2Roles = processor.SelectObject<string[]>(dataModel, xpathString);
                VerifyEnumerable(dataModel.Users[2].Roles, user2Roles, xpathString);

                xpathString = "/Users[2]";
                UserInfo user2 = processor.SelectObject<UserInfo>(dataModel, xpathString);
                Verify(dataModel.Users[2], user2, xpathString);
        
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message);
            }
        }

        static void SingleObjectMultiObjectTraceTest()
        {
            XPathParser parser = new XPathParser();

            try
            {
                List<object> objectBranch = CreateObjectBranch();

                XpathProcessor processor = new XpathProcessor();

                {
                    List<PathElement> xpath = parser.Parse("/Message");
                    string message = processor.SelectObject<string>(objectBranch, xpath);
                }

                string message2 = processor.SelectObject<string>(objectBranch, "Message");
                //string message3 = processor.SelectObject<string>(objectBranch, "//Message");
                int messageLength = processor.SelectObject<int>(objectBranch, "/Message/Length");
                string[] availableRoles1 = processor.SelectObject<string[]>(objectBranch, "/AvailableRoles");
                string[] availableRoles3 = processor.SelectObject<string[]>(objectBranch, "AvailableRoles");
                string role2 = processor.SelectObject<string>(objectBranch, "/AvailableRoles[2]");
                List<string> options = processor.SelectObject<List<string>>(objectBranch, "/Options");
                int optionsCount = processor.SelectObject<int>(objectBranch, "/Options/Count");
                string option1 = processor.SelectObject<string>(objectBranch, "/Options[1]");
                int option1Length = processor.SelectObject<int>(objectBranch, "/Options[1]/Length");
                string organization1 = processor.SelectObject<string>(objectBranch, "/Organizations[org1]");
                string[] user2Roles = processor.SelectObject<string[]>(objectBranch, "/Users[2]/Roles");
                UserInfo user2 = processor.SelectObject<UserInfo>(objectBranch, "/Users[2]");
                string[] anyUserRoles = processor.SelectObject<string[]>(objectBranch, "/*/Roles");

            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message);
            }
        }

        static List<object> CreateObjectBranch()
        {
            List<object> objectBranch = new List<object>();

            DataModel dataModel1 = new DataModel();
            dataModel1.Initialize1();
            objectBranch.Add(dataModel1);

            DataModel dataModel2 = new DataModel();
            dataModel2.Initialize2();
            objectBranch.Add(dataModel2);

            DataModel dataModel3 = new DataModel();
            dataModel3.Initialize3();
            objectBranch.Add(dataModel3);

            return objectBranch;
        }
    }
}
